<template>
	<div ref="statsRef" class="statistics"></div>
	<div ref="containerRef" class="container"></div>
</template>

<script lang="ts" setup>
import {onMounted, ref, watch} from 'vue';
import {AxesHelper, Color, MeshBasicMaterial, PerspectiveCamera, PlaneGeometry, Scene, WebGLRenderer, Mesh, BoxGeometry, SphereGeometry, SpotLight, MeshLambertMaterial, MeshPhongMaterial, DoubleSide, PointLight, AmbientLight, Fog, BufferGeometry, CylinderGeometry, OctahedronGeometry, TetrahedronGeometry, TorusGeometry, OrthographicCamera, Vector3} from 'three';
import Stats from 'stats.js';
import * as dat from 'dat.gui';
import { createMultiMaterialObject } from 'three/examples/jsm/utils/SceneUtils';

const stats = new Stats();

// stats.dom.style.top = '50px';
stats.showPanel(0);
	
const containerRef = ref<HTMLDivElement>();
const statsRef = ref<HTMLDivElement>();
const scene = new Scene();
const renderer = new WebGLRenderer();

// renderer.setClearColor(new Color(0xeeeeee));
renderer.setClearColor(0xeeeeee);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;

const cubeGeometry = new BoxGeometry(4, 4, 4);

const cubeMaterial = new MeshLambertMaterial({
// const cubeMaterial = new MeshBasicMaterial({
	color: 0xff0000,
	wireframe: false,
});

const cube = new Mesh(cubeGeometry, cubeMaterial);

cube.castShadow = true;
cube.position.set(2, 2, 2);
scene.add(cube);

/**
* 光源设置
*/
//聚光灯
const spotLight = new SpotLight(0xffffff, 10000);

spotLight.position.set(-40, 30, -30);
spotLight.castShadow = true;
scene.add(spotLight);

const axes = new AxesHelper(20);

scene.add(axes);

const planeGeometry = new PlaneGeometry(60, 40);
const meshBasicMaterial = new MeshLambertMaterial({color: 0xffffff});
// const meshBasicMaterial = new MeshBasicMaterial({color: 0xcccccc});
const plane = new Mesh(planeGeometry, meshBasicMaterial);

plane.receiveShadow = true;
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0;
scene.add(plane);

for(let j = 0; j < planeGeometry.parameters.height / 2; j++){
	for(let i = 0; i < planeGeometry.parameters.width / 2; i++){
		const cube = new Mesh(cubeGeometry, cubeMaterial);
		
		cube.castShadow = true;
		cube.position.z = -(planeGeometry.parameters.height / 2) + 2 + j * 5;
		cube.position.x = -(planeGeometry.parameters.width / 2) + 2 + i * 5;
		cube.position.y = 0;
		scene.add(cube);
	}
}

const sphereGeometry = new SphereGeometry(4);

const sphereMaterial = new MeshLambertMaterial({
// const sphereMaterial = new MeshBasicMaterial({
	color: 0x7777ff,
	wireframe: false,
});

const sphere = new Mesh(sphereGeometry, sphereMaterial);

sphere.castShadow = true;
sphere.position.x = 20;
sphere.position.y = 4;
sphere.position.z = 2;
scene.add(sphere);

const lookAtGeom = new SphereGeometry(4);

const lookAtMesh = new Mesh(lookAtGeom, new MeshLambertMaterial({
	color: 0x00ff00,
}));

scene.add(lookAtMesh);

const controlRef = ref({
	rotationSpeed: 0.02,
	bouncingSpeed: 0.03,
	numberOfObjects: 0,
	scaleX: 1,
	scaleY: 1,
	scaleZ: 1,
	positionX: 1,
	positionY: 1,
	positionZ: 1,
	translateX: 0,
	translateY: 0,
	translateZ: 0,
	obj: {
		x: 0,
		y: 0,
		z: 0,
	},
	camera: 'Perspective',
	addCube: function(){
		const cubeGeometry = new BoxGeometry(4, 4, 4);
		const cube = new Mesh(cubeGeometry, cubeMaterial);
		
		cube.name = 'cube-' + scene.children.length;
		cube.castShadow = true;
		cube.position.x = -30 + Math.round(Math.random() * 60);
		cube.position.y = Math.round(Math.random() * 5);
		cube.position.z = -20 + Math.round(Math.random() * 40);
		scene.add(cube);
		this.numberOfObjects = scene.children.length;
	},
	remove: function(){
		const allChildren = scene.children;
		const lastObject = allChildren[allChildren.length - 1];
		
		if(lastObject instanceof Mesh && lastObject.name.startsWith('cube')){
			//mesh 网格模型，且名称以 cube 开头，新添加的立方体
			scene.remove(lastObject);
		}
		
		this.numberOfObjects = scene.children.length;
	},
	addFog: function(){
		scene.fog = new Fog(0xffffff, 0.015, 100);
		this.numberOfObjects = scene.children.length;
	},
	removeFog: function(){
		scene.fog = null;
		this.numberOfObjects = scene.children.length;
	},
	toggleMaterial: function(){
		if(!scene.overrideMaterial){
			//初始材质状态
			scene.overrideMaterial = new MeshLambertMaterial({
				color: 0xffffff,
			});
		}else{
			//重写材质状态
			scene.overrideMaterial = null;
		}
		
		this.numberOfObjects = scene.children.length;
	},
	translate: function(){
		this.obj.x = this.translateX;
		this.obj.y = this.translateY;
		this.obj.z = this.translateZ;
	},
	switchCamera: function(){
		if(this.camera === 'Perspective'){
			//当前是透视相机
			this.camera = 'Orthographic';
		}else{
			//当前是正交相机
			this.camera = 'Perspective';
		}
	},
});

if(document.querySelectorAll('.dg.ac>.dg.main.a').length === 0){
	//还未初始化图形用户界面
	window.gui = new dat.GUI();
	window.gui.add(controlRef.value, 'rotationSpeed', 0, 0.5);
	window.gui.add(controlRef.value, 'bouncingSpeed', 0, 0.5);
	window.gui.add(controlRef.value, 'numberOfObjects').listen();
	window.gui.add(controlRef.value, 'addCube');
	window.gui.add(controlRef.value, 'remove');
	window.gui.add(controlRef.value, 'addFog');
	window.gui.add(controlRef.value, 'removeFog');
	window.gui.add(controlRef.value, 'toggleMaterial');
	window.gui.add(controlRef.value, 'camera').listen();
	window.gui.add(controlRef.value, 'switchCamera');
	
	const scaleFolder = window.gui.addFolder('scale');
	
	scaleFolder.add(controlRef.value, 'scaleX', 0, 5);
	scaleFolder.add(controlRef.value, 'scaleY', 0, 5);
	scaleFolder.add(controlRef.value, 'scaleZ', 0, 5);
	
	const positionFolder = window.gui.addFolder('position');
	
	positionFolder.add(controlRef.value, 'positionX', -5, 5);
	positionFolder.add(controlRef.value, 'positionY', -5, 5);
	positionFolder.add(controlRef.value, 'positionZ', -5, 5);
	
	const translateFolder = window.gui.addFolder('translate');
	
	translateFolder.add(controlRef.value, 'translateX', -5, 5);
	translateFolder.add(controlRef.value, 'translateY', -5, 5);
	translateFolder.add(controlRef.value, 'translateZ', -5, 5);
	translateFolder.add(controlRef.value, 'translate');
}

watch(
	() => controlRef.value.scaleX,
	(n) => {
		cube.scale.setX(n);
	}
);

watch(
	() => controlRef.value.scaleY,
	(n) => {
		cube.scale.setY(n);
	}
);

watch(
	() => controlRef.value.scaleZ,
	(n) => {
		cube.scale.setZ(n);
	}
);

watch(
	() => controlRef.value.positionX,
	(n) => {
		cube.position.setX(n);
	}
);

watch(
	() => controlRef.value.positionY,
	(n) => {
		cube.position.setY(n);
	}
);

watch(
	() => controlRef.value.positionZ,
	(n) => {
		cube.position.setZ(n);
	}
);

watch(
	() => controlRef.value.obj,
	(n) => {
		console.log('obj:');
		console.log(n);
		console.log('n.x:');
		console.log(n.x);
		cube.translateX(n.x);
		cube.translateY(n.y);
		cube.translateZ(n.z);
	},
	{
		deep: true,
	}
);

watch(
	() => controlRef.value.camera,
	(n) => {
		if(n === 'Orthographic'){
			//改为正交相机
			cameraRef.value = new OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
			cameraRef.value.position.set(-90, 40, 130);
			cameraRef.value.lookAt(scene.position);
		}else{
			//改为透视相机
			cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
			cameraRef.value.position.set(-90, 40, 130);
			cameraRef.value.lookAt(scene.position);
		}
	}
);

let step = 0;
let stepCamera = 0;
const cameraRef = ref<PerspectiveCamera | OrthographicCamera>();

function renderScene(){
	stats.update();
	
	if(cameraRef.value){
		//存在相机
		stepCamera += 0.02;
		
		const x = 10 + 100 * Math.sin(stepCamera);
		// const x = 10 + 100 * Math.cos(stepCamera);
		const v3 = new Vector3(x, 4, 0);
		
		lookAtMesh.position.copy(v3);
		// cameraRef.value.lookAt(x, 4, 0);
		cameraRef.value.lookAt(v3);
	}
	
	scene.traverse((e) => {
		/* if(e instanceof Mesh && e != plane){
			//mesh 网格模型，且不是平面
			e.rotation.x += controlRef.value.rotationSpeed;
			e.rotation.y += controlRef.value.rotationSpeed;
			e.rotation.z += controlRef.value.rotationSpeed;
		} */
		
		if(e.name.startsWith('cube')){
			//名称以 cube 开头，新添加的立方体
			e.rotation.x += controlRef.value.rotationSpeed;
			e.rotation.y += controlRef.value.rotationSpeed;
			e.rotation.z += controlRef.value.rotationSpeed;
		}
	});
	
	cube.rotation.x += controlRef.value.rotationSpeed;
	cube.rotation.y += controlRef.value.rotationSpeed;
	cube.rotation.z += controlRef.value.rotationSpeed;
	// cube.scale.x += 0.01;
	step += controlRef.value.bouncingSpeed;
	sphere.position.x = 20 + 10 * Math.cos(step);
	sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));
	requestAnimationFrame(renderScene);
	
	if(cameraRef.value){
		//存在相机
		renderer.render(scene, cameraRef.value);
	}
}

renderScene();

window.addEventListener('resize', () => {
	if(cameraRef.value instanceof PerspectiveCamera){
		//透视相机
		cameraRef.value.aspect = window.innerWidth / window.innerHeight;
	}
	
	cameraRef.value.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}, false);

onMounted(() => {
	cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
	
	cameraRef.value.position.set(-90, 40, 130);
	cameraRef.value.lookAt(scene.position);
	statsRef.value?.append(stats.dom);
	containerRef.value?.appendChild(renderer.domElement);
	renderer.render(scene, cameraRef.value);
});
</script>

<style scoped>
</style>